home *** CD-ROM | disk | FTP | other *** search
/ PC World 2008 September / PCWorld_2008-09_cd.bin / v cisle / sadanastroju / lightning-0.8-tb-win.xpi / chrome / calendar.jar / content / calendar / calendar-invitations-manager.js < prev    next >
Text File  |  2008-01-16  |  22KB  |  556 lines

  1. /* ***** BEGIN LICENSE BLOCK *****
  2.  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  3.  *
  4.  * The contents of this file are subject to the Mozilla Public License Version
  5.  * 1.1 (the "License"); you may not use this file except in compliance with
  6.  * the License. You may obtain a copy of the License at
  7.  * http://www.mozilla.org/MPL/
  8.  *
  9.  * Software distributed under the License is distributed on an "AS IS" basis,
  10.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  11.  * for the specific language governing rights and limitations under the
  12.  * License.
  13.  *
  14.  * The Original Code is Sun Microsystems code.
  15.  *
  16.  * The Initial Developer of the Original Code is Sun Microsystems.
  17.  * Portions created by the Initial Developer are Copyright (C) 2006
  18.  * the Initial Developer. All Rights Reserved.
  19.  *
  20.  * Contributor(s):
  21.  *   Thomas Benisch <thomas.benisch@sun.com>
  22.  *   Philipp Kewisch <mozilla@kewis.ch>
  23.  *
  24.  * Alternatively, the contents of this file may be used under the terms of
  25.  * either the GNU General Public License Version 2 or later (the "GPL"), or
  26.  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  27.  * in which case the provisions of the GPL or the LGPL are applicable instead
  28.  * of those above. If you wish to allow use of your version of this file only
  29.  * under the terms of either the GPL or the LGPL, and not to allow others to
  30.  * use your version of this file under the terms of the MPL, indicate your
  31.  * decision by deleting the provisions above and replace them with the notice
  32.  * and other provisions required by the GPL or the LGPL. If you do not delete
  33.  * the provisions above, a recipient may use your version of this file under
  34.  * the terms of any one of the MPL, the GPL or the LGPL.
  35.  *
  36.  * ***** END LICENSE BLOCK ***** */
  37.  
  38. var gInvitationsRequestManager = null;
  39.  
  40. function getInvitationsRequestManager() {
  41.     if (!gInvitationsRequestManager) {
  42.         gInvitationsRequestManager = new InvitationsRequestManager();
  43.     }
  44.     return gInvitationsRequestManager;
  45. }
  46.  
  47. function InvitationsRequestManager() {
  48.     this.mRequestStatusList = {};
  49. }
  50.  
  51. InvitationsRequestManager.prototype = {
  52.     mRequestStatusList: null,
  53.  
  54.     getRequestStatus: function IRM_getRequestStatus(calendar) {
  55.         var calendarId = this._getCalendarId(calendar);
  56.         if (calendarId in this.mRequestStatusList) {
  57.             return this.mRequestStatusList[calendarId];
  58.         }
  59.         return null;
  60.     },
  61.  
  62.     addRequestStatus: function IRM_addRequestStatus(calendar, requestStatus) {
  63.         var calendarId = this._getCalendarId(calendar);
  64.         this.mRequestStatusList[calendarId] = requestStatus;
  65.     },
  66.  
  67.     deleteRequestStatus: function IRM_deleteRequestStatus(calendar) {
  68.         var calendarId = this._getCalendarId(calendar);
  69.         if (calendarId in this.mRequestStatusList) {
  70.             delete this.mRequestStatusList[calendarId];
  71.         }
  72.     },
  73.  
  74.     getPendingRequests: function IRM_getPendingRequests() {
  75.         var count = 0;
  76.         for each (var requestStatus in this.mRequestStatusList) {
  77.             var request = requestStatus.request;
  78.             if (request && request.isPending) {
  79.                 count++;
  80.             }
  81.         }
  82.         return count;
  83.     },
  84.  
  85.     cancelPendingRequests: function IRM_cancelPendingRequests() {
  86.         for each (var requestStatus in this.mRequestStatusList) {
  87.             var request = requestStatus.request;
  88.             if (request && request.isPending) {
  89.                 request.cancel(null);
  90.             }
  91.         }
  92.     },
  93.  
  94.     _getCalendarId: function IRM__getCalendarId(calendar) {
  95.         return encodeURIComponent(calendar.uri.spec);
  96.     }
  97. };
  98.  
  99. var gInvitationsManager = null;
  100.  
  101. function getInvitationsManager() {
  102.     if (!gInvitationsManager) {
  103.         gInvitationsManager = new InvitationsManager();
  104.     }
  105.     return gInvitationsManager;
  106. }
  107.  
  108. function InvitationsManager() {
  109.     this.mItemList = new Array();
  110.     this.mOperationListeners = new Array();
  111.     this.mStartDate = null;
  112.     this.mJobsPending = 0;
  113.     this.mTimer = null;
  114.     this.mUnregisteredCalendars = new Array();
  115.     var calendarManagerObserver = {
  116.         mInvitationsManager: this,
  117.         onCalendarRegistered: function(aCalendar) {
  118.         },
  119.         onCalendarUnregistering: function(aCalendar) {
  120.             this.mInvitationsManager.unregisterCalendar(aCalendar);
  121.         },
  122.         onCalendarDeleting: function(aCalendar) {
  123.         }
  124.     };
  125.     getCalendarManager().addObserver(calendarManagerObserver);
  126. }
  127.  
  128. InvitationsManager.prototype = {
  129.     mItemList: null,
  130.     mOperationListeners: null,
  131.     mStartDate: null,
  132.     mJobsPending: 0,
  133.     mTimer: null,
  134.     mUnregisteredCalendars: null,
  135.  
  136.     scheduleInvitationsUpdate: function IM_scheduleInvitationsUpdate(firstDelay,
  137.                                                                      repeatDelay,
  138.                                                                      operationListener) {
  139.         if (this.mTimer) {
  140.             this.mTimer.cancel();
  141.         } else {
  142.             this.mTimer = Components.classes["@mozilla.org/timer;1"]
  143.                           .createInstance(Components.interfaces.nsITimer);
  144.         }
  145.         var callback = {
  146.             mInvitationsManager: this,
  147.             mRepeatDelay: repeatDelay,
  148.             mOperationListener: operationListener,
  149.             notify: function(timer) {
  150.                 if (timer.delay != this.mRepeatDelay) {
  151.                     timer.delay = this.mRepeatDelay;
  152.                 }
  153.                 this.mInvitationsManager.getInvitations(
  154.                     true, this.mOperationListener);
  155.             }
  156.         };
  157.         this.mTimer.initWithCallback(callback, firstDelay,
  158.             this.mTimer.TYPE_REPEATING_SLACK);
  159.     },
  160.  
  161.     cancelInvitationsUpdate: function IM_cancelInvitationsUpdate() {
  162.         if (this.mTimer) {
  163.             this.mTimer.cancel();
  164.         }
  165.     },
  166.  
  167.     getInvitations: function IM_getInvitations(suppressOnError,
  168.                                                operationListener1,
  169.                                                operationListener2) {
  170.         if (operationListener1) {
  171.             this.addOperationListener(operationListener1);
  172.         }
  173.         if (operationListener2) {
  174.             this.addOperationListener(operationListener2);
  175.         }
  176.         this.updateStartDate();
  177.         var requestManager = getInvitationsRequestManager();
  178.         var calendars = getCalendarManager().getCalendars({});
  179.         for each (var calendar in calendars) {
  180.             try {
  181.                 // temporary hack unless all group scheduling features are supported
  182.                 // by the caching facade (calCachedCalendar):
  183.                 var wcapCalendar = calendar.getProperty("private.wcapCalendar")
  184.                                            .QueryInterface(Components.interfaces.calIWcapCalendar);
  185.                 if (!wcapCalendar.isOwnedCalendar) {
  186.                     continue;
  187.                 }
  188.                 var listener = {
  189.                     mRequestManager: requestManager,
  190.                     mInvitationsManager: this,
  191.  
  192.                     QueryInterface: function(aIID) {
  193.                         if (!aIID.equals(Components.interfaces.nsISupports) &&
  194.                             !aIID.equals(Components.interfaces.calIOperationListener) &&
  195.                             !aIID.equals(Components.interfaces.calIObserver)) {
  196.                             throw Components.results.NS_ERROR_NO_INTERFACE;
  197.                         }
  198.                         return this;
  199.                     },
  200.  
  201.                     // calIOperationListener
  202.                     onOperationComplete: function(aCalendar,
  203.                                                   aStatus,
  204.                                                   aOperationType,
  205.                                                   aId,
  206.                                                   aDetail) {
  207.  
  208.                         if (aOperationType != Components.interfaces.calIOperationListener.GET &&
  209.                             aOperationType != Components.interfaces.calIWcapCalendar.SYNC) {
  210.                             return;
  211.                         }
  212.                         var requestStatus =
  213.                             this.mRequestManager.getRequestStatus(aCalendar);
  214.                         if (Components.isSuccessCode(aStatus)) {
  215.                             if (requestStatus.firstRequest) {
  216.                                 requestStatus.firstRequest = false;
  217.                                 requestStatus.lastUpdate =
  218.                                     requestStatus.firstRequestStarted;
  219.                             } else {
  220.                                 requestStatus.lastUpdate = aDetail;
  221.                             }
  222.                         }
  223.                         if (this.mRequestManager.getPendingRequests() == 0) {
  224.                             this.mInvitationsManager
  225.                                 .deleteUnregisteredCalendarItems();
  226.                             this.mInvitationsManager.mItemList.sort(
  227.                                 function (a, b) {
  228.                                     var dateA = a.startDate.getInTimezone(calendarDefaultTimezone());
  229.                                     var dateB = b.startDate.getInTimezone(calendarDefaultTimezone());
  230.                                     return dateA.compare(dateB);
  231.                                 });
  232.                             var listener;
  233.                             while ((listener = this.mInvitationsManager.mOperationListeners.shift())) {
  234.                                 listener.onGetResult(
  235.                                     null,
  236.                                     Components.results.NS_OK,
  237.                                     Components.interfaces.calIItemBase,
  238.                                     null,
  239.                                     this.mInvitationsManager.mItemList.length,
  240.                                     this.mInvitationsManager.mItemList);
  241.                                 listener.onOperationComplete(
  242.                                     null,
  243.                                     Components.results.NS_OK,
  244.                                     Components.interfaces.calIOperationListener.GET,
  245.                                     null,
  246.                                     null);
  247.                             }
  248.                         }
  249.                     },
  250.  
  251.                     onGetResult: function(aCalendar,
  252.                                           aStatus,
  253.                                           aItemType,
  254.                                           aDetail,
  255.                                           aCount,
  256.                                           aItems) {
  257.                         if (!Components.isSuccessCode(aStatus)) {
  258.                             return;
  259.                         }
  260.                         for each (var item in aItems) {
  261.                             this.mInvitationsManager.addItem(item);
  262.                         }
  263.                     },
  264.  
  265.                     // calIObserver
  266.                     onStartBatch: function() {
  267.                     },
  268.  
  269.                     onEndBatch: function() {
  270.                     },
  271.  
  272.                     onLoad: function() {
  273.                     },
  274.  
  275.                     onAddItem: function(aItem) {
  276.                         this.mInvitationsManager.addItem(aItem);
  277.                     },
  278.  
  279.                     onModifyItem: function(aNewItem, aOldItem) {
  280.                         this.mInvitationsManager.deleteItem(aNewItem);
  281.                         this.mInvitationsManager.addItem(aNewItem);
  282.                     },
  283.  
  284.                     onDeleteItem: function(aDeletedItem) {
  285.                         this.mInvitationsManager.deleteItem(aDeletedItem);
  286.                     },
  287.  
  288.                     onError: function(aErrNo, aMessage) {
  289.                     },
  290.  
  291.                     onPropertyChanged: function(aCalendar, aName, aValue, aOldValue) {
  292.                     },
  293.  
  294.                     onPropertyDeleting: function(aCalendar, aName) {
  295.                     }
  296.                 };
  297.                 var requestStatus =
  298.                     requestManager.getRequestStatus(wcapCalendar);
  299.                 if (!requestStatus) {
  300.                     requestStatus = {
  301.                         request: null,
  302.                         firstRequest: true,
  303.                         firstRequestStarted: null,
  304.                         lastUpdate: null
  305.                     };
  306.                     requestManager.addRequestStatus(wcapCalendar,
  307.                                                     requestStatus);
  308.                 }
  309.                 if (!requestStatus.request ||
  310.                     !requestStatus.request.isPending) {
  311.                     var filter = (suppressOnError ?
  312.                                   wcapCalendar.ITEM_FILTER_SUPPRESS_ONERROR :
  313.                                   0);
  314.                     var request;
  315.                     if (requestStatus.firstRequest) {
  316.                         requestStatus.firstRequestStarted = this.getDate();
  317.                         filter |= wcapCalendar.ITEM_FILTER_REQUEST_NEEDS_ACTION;
  318.                         request = wcapCalendar.wrappedJSObject.getItems(filter,
  319.                             0, this.mStartDate, null, listener);
  320.                     } else {
  321.                         filter |= wcapCalendar.ITEM_FILTER_TYPE_EVENT;
  322.                         request = wcapCalendar.syncChangesTo(null, filter,
  323.                             requestStatus.lastUpdate, listener);
  324.                     }
  325.                     requestStatus.request = request;
  326.                 }
  327.             } catch (e) {
  328.             }
  329.         }
  330.  
  331.         if (requestManager.getPendingRequests() == 0) {
  332.             this.deleteUnregisteredCalendarItems();
  333.             var listener;
  334.             while ((listener = this.mOperationListeners.shift())) {
  335.                 listener.onOperationComplete(
  336.                     null,
  337.                     Components.results.NS_ERROR_FAILURE,
  338.                     Components.interfaces.calIOperationListener.GET,
  339.                     null,
  340.                     null );
  341.             }
  342.         }
  343.     },
  344.  
  345.     openInvitationsDialog: function IM_openInvitationsDialog(onLoadOpListener,
  346.                                                              finishedCallBack) {
  347.         var args = new Object();
  348.         args.onLoadOperationListener = onLoadOpListener;
  349.         args.queue = new Array();
  350.         args.finishedCallBack = finishedCallBack;
  351.         args.requestManager = getInvitationsRequestManager();
  352.         args.invitationsManager = this;
  353.         // the dialog will reset this to auto when it is done loading
  354.         window.setCursor("wait");
  355.         // open the dialog modally
  356.         window.openDialog(
  357.             "chrome://calendar/content/calendar-invitations-dialog.xul",
  358.             "_blank",
  359.             "chrome,titlebar,modal,resizable",
  360.             args);
  361.     },
  362.  
  363.     processJobQueue: function IM_processJobQueue(queue,
  364.                                                  jobQueueFinishedCallBack) {
  365.         // TODO: undo/redo
  366.         var operationListener = {
  367.             mInvitationsManager: this,
  368.             mJobQueueFinishedCallBack: jobQueueFinishedCallBack,
  369.  
  370.             onOperationComplete: function (aCalendar,
  371.                                            aStatus,
  372.                                            aOperationType,
  373.                                            aId,
  374.                                            aDetail) {
  375.                 if (Components.isSuccessCode(aStatus) &&
  376.                     aOperationType == Components.interfaces.calIOperationListener.MODIFY) {
  377.                     this.mInvitationsManager.deleteItem(aDetail);
  378.                     this.mInvitationsManager.addItem(aDetail);
  379.                 }
  380.                 this.mInvitationsManager.mJobsPending--;
  381.                 if (this.mInvitationsManager.mJobsPending == 0 &&
  382.                     this.mJobQueueFinishedCallBack) {
  383.                     this.mJobQueueFinishedCallBack();
  384.                 }
  385.             },
  386.  
  387.             onGetResult: function(aCalendar,
  388.                                   aStatus,
  389.                                   aItemType,
  390.                                   aDetail,
  391.                                   aCount,
  392.                                   aItems) {
  393.  
  394.             }
  395.         };
  396.         this.mJobsPending = 0;
  397.         for (var i = 0; i < queue.length; i++) {
  398.             var job = queue[i];
  399.             var oldItem = job.oldItem;
  400.             var newItem = job.newItem;
  401.             switch (job.action) {
  402.                 case 'modify':
  403.                     this.mJobsPending++;
  404.                     newItem.calendar.modifyItem(newItem,
  405.                                                 oldItem,
  406.                                                 operationListener);
  407.                     break;
  408.                 default:
  409.                     break;
  410.             }
  411.         }
  412.         if (this.mJobsPending == 0 && jobQueueFinishedCallBack) {
  413.             jobQueueFinishedCallBack();
  414.         }
  415.     },
  416.  
  417.     hasItem: function IM_hasItem(item) {
  418.         for (var i = 0; i < this.mItemList.length; ++i) {
  419.             if (this.mItemList[i].hashId == item.hashId) {
  420.                 return true;
  421.             }
  422.         }
  423.         return false;
  424.     },
  425.  
  426.     addItem: function IM_addItem(item) {
  427.         var recInfo = item.recurrenceInfo;
  428.         if (recInfo && this.getParticipationStatus(item) != "NEEDS-ACTION") {
  429.             var ids = recInfo.getExceptionIds({});
  430.             for each (var id in ids) {
  431.                 var ex = recInfo.getExceptionFor(id, false);
  432.                 if (ex && this.validateItem(ex) && !this.hasItem(ex)) {
  433.                     this.mItemList.push(ex);
  434.                 }
  435.             }
  436.         } else if (this.validateItem(item) && !this.hasItem(item)) {
  437.             this.mItemList.push(item);
  438.         }
  439.     },
  440.  
  441.     deleteItem: function IM_deleteItem(item) {
  442.         var i = 0;
  443.         while (i < this.mItemList.length) {
  444.             // Delete all items with the same id from the list.
  445.             // If item is a recurrent event, also all exceptions are deleted.
  446.             if (this.mItemList[i].id == item.id) {
  447.                 this.mItemList.splice(i, 1);
  448.             } else {
  449.                 i++;
  450.             }
  451.         }
  452.     },
  453.  
  454.     addOperationListener: function IM_addOperationListener(operationListener) {
  455.         for each (var listener in this.mOperationListeners) {
  456.             if (listener == operationListener) {
  457.                 return false;
  458.             }
  459.         }
  460.         this.mOperationListeners.push(operationListener);
  461.         return true;
  462.     },
  463.  
  464.     getDate: function IM_getDate() {
  465.         var date = Components.classes["@mozilla.org/calendar/datetime;1"]
  466.                    .createInstance(Components.interfaces.calIDateTime);
  467.         date.jsDate = new Date();
  468.         return date;
  469.     },
  470.  
  471.     getStartDate: function IM_getStartDate() {
  472.         var date = Components.classes["@mozilla.org/calendar/datetime;1"]
  473.                    .createInstance(Components.interfaces.calIDateTime);
  474.         date.jsDate = new Date();
  475.         date = date.getInTimezone(calendarDefaultTimezone());
  476.         date.hour = 0;
  477.         date.minute = 0;
  478.         date.second = 0;
  479.         return date;
  480.     },
  481.  
  482.     updateStartDate: function IM_updateStartDate() {
  483.         if (!this.mStartDate) {
  484.             this.mStartDate = this.getStartDate();
  485.         } else {
  486.             var startDate = this.getStartDate();
  487.             if (startDate.compare(this.mStartDate) > 0) {
  488.                 this.mStartDate = startDate;
  489.                 var i = 0;
  490.                 while (i < this.mItemList.length) {
  491.                     if (!this.validateItem(this.mItemList[i])) {
  492.                         this.mItemList.splice(i, 1);
  493.                     } else {
  494.                         i++;
  495.                     }
  496.                 }
  497.             }
  498.         }
  499.     },
  500.  
  501.     validateItem: function IM_validateItem(item) {
  502.         var participationStatus = this.getParticipationStatus(item);
  503.         if (participationStatus != "NEEDS-ACTION") {
  504.             return false;
  505.         }
  506.         if (item.recurrenceInfo) {
  507.             return true;
  508.         } else {
  509.             var startDate = item.startDate
  510.                                 .getInTimezone(calendarDefaultTimezone());
  511.             if (startDate.compare(this.mStartDate) >= 0) {
  512.                 return true;
  513.             }
  514.         }
  515.         return false;
  516.     },
  517.  
  518.     getParticipationStatus: function IM_getParticipationStatus(item) {
  519.         try {
  520.             // temporary hack unless all group scheduling features are supported
  521.             // by the caching facade (calCachedCalendar):
  522.             var wcapCalendar = item.calendar.getProperty("private.wcapCalendar")
  523.                                             .QueryInterface(Components.interfaces.calIWcapCalendar);
  524.             var attendee = wcapCalendar.getInvitedAttendee(item);
  525.             if (attendee)
  526.                 return attendee.participationStatus;
  527.         } catch (e) {}
  528.         return null;
  529.     },
  530.  
  531.     unregisterCalendar: function IM_unregisterCalendar(calendar) {
  532.         try {
  533.             var wcapCalendar = calendar.QueryInterface(
  534.                 Components.interfaces.calIWcapCalendar);
  535.             this.mUnregisteredCalendars.push(wcapCalendar);
  536.         } catch (e) {}
  537.     },
  538.  
  539.     deleteUnregisteredCalendarItems: function IM_deleteUnregisteredCalendarItems() {
  540.         var calendar;
  541.         while ((calendar = this.mUnregisteredCalendars.shift())) {
  542.             // delete all unregistered calendar items
  543.             var i = 0;
  544.             while (i < this.mItemList.length) {
  545.                 if (this.mItemList[i].calendar.uri.equals(calendar.uri)) {
  546.                     this.mItemList.splice(i, 1);
  547.                 } else {
  548.                     i++;
  549.                 }
  550.             }
  551.             // delete unregistered calendar request status entry
  552.             getInvitationsRequestManager().deleteRequestStatus(calendar);
  553.         }
  554.     }
  555. };
  556.